package com.qiguliuxing.dts.service.seckill;

import com.google.common.collect.Maps;
import com.qiguliuxing.dts.common.constant.CommConsts;
import com.qiguliuxing.dts.common.type.BatchStatusEnum;
import com.qiguliuxing.dts.db.bean.SeckillGoodsVo;
import com.qiguliuxing.dts.db.bean.TimeBatchConfig;
import com.qiguliuxing.dts.db.domain.DtsCart;
import com.qiguliuxing.dts.db.domain.DtsGoodsProduct;
import com.qiguliuxing.dts.db.domain.DtsGoodsSpecification;
import com.qiguliuxing.dts.db.domain.DtsSeckillBatch;
import com.qiguliuxing.dts.service.base.DtsGoodsSpecificationService;
import com.qiguliuxing.dts.service.base.DtsUserSeckillSubService;
import com.qiguliuxing.dts.service.seckill.model.ShapeLinkList;
import com.qiguliuxing.dts.service.seckill.model.SeckillStatus;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotNull;
import java.text.ParseException;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 秒杀服务
 *
 * @author 1197673878@qq.com
 * @category 秒杀服务
 * @since 2020年10月13日 上午12:00:34
 */
@Service
public class WxSeckillService {

    @Autowired
    private DtsUserSeckillSubService dtsUserSeckillSubService;

    @Autowired
    private SeckillGoodsService seckillGoodsService;

    private final static String DAY_PATTERN = "yyyy-MM-dd";
    private final static String DAY_HH_MM_PATTERN = "yyyy-MM-dd HH:mm:ss";
    private final static String HH_MM_SS = "HH:mm:ss";

    /**
     * 秒杀批次列表
     *
     * @return 批次列表数据
     * @throws ParseException
     */
    public Object secondSeckillBatchInfo() {
        Map<String, Object> map = Maps.newHashMapWithExpectedSize(CommConsts.INIT_HASH_MAP_SIZE);
        List<DtsSeckillBatch> listConfig = this.getTimeBatchConfigs();

        int size = listConfig.size();
        final int indexAct = this.calcCurrentIndexAct();

        ShapeLinkList<TimeBatchConfig> shapeLinkList = new ShapeLinkList<TimeBatchConfig>();
        listConfig.forEach(item -> {
            TimeBatchConfig timeBatchConfig = new TimeBatchConfig();
            BeanUtils.copyProperties(item, timeBatchConfig);
            shapeLinkList.add(timeBatchConfig);
        });
        List<TimeBatchConfig> listTimeConfig = shapeLinkList.get(indexAct, size);
        listTimeConfig.forEach(item -> {
            calEveryItem(indexAct, item);
        });
        map.put("seckillTime", listTimeConfig);
        map.put("seckillTimeIndex", 0);
        return map;
    }

    /**
     * 秒杀配置
     *
     * @return 批次信息
     */
    public List<DtsSeckillBatch> getTimeBatchConfigs() {
        return seckillGoodsService.getTimeBatchConfigs();
    }

    /**
     * 当前批次ID
     *
     * @return 当前批次ID
     */
    private int calcCurrentIndexAct() {
        List<DtsSeckillBatch> listConfig = this.getTimeBatchConfigs();
        List<DtsSeckillBatch> curBatchConfigs = listConfig.stream().filter(item -> this.inBatchTime(item)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(curBatchConfigs)) {
            return NumberUtils.INTEGER_ZERO;
        }
        return curBatchConfigs.get(0).getId();
    }

    /**
     * 计算当前时间内的批次信息
     *
     * @param config
     * @return
     */
    public boolean inBatchTime(DtsSeckillBatch config) {
        long curMills = System.currentTimeMillis();
        String day = DateFormatUtils.format(new Date(), DAY_PATTERN);
        try {
            long startTime = DateUtils.parseDate(day + " " + config.getStartTime().format(DateTimeFormatter.ofPattern(HH_MM_SS)), DAY_HH_MM_PATTERN).getTime();
            long endTime = DateUtils.parseDate(day + " " + config.getEndTime().format(DateTimeFormatter.ofPattern(HH_MM_SS)), DAY_HH_MM_PATTERN).getTime();
            return curMills <= endTime && curMills > startTime;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 计算批次的状态
     *
     * @param indexAct 当前批次id
     * @param item     批次项
     */
    private void calEveryItem(int indexAct, TimeBatchConfig item) {
        LocalTime endTime = item.getEndTime();
        long nano = endTime.toSecondOfDay();
        int sort = item.getSort();
        if (sort == indexAct) {
            item.setState(BatchStatusEnum.IN_LINE.getDesc());
        }
        if (sort > indexAct) {
            item.setState(BatchStatusEnum.UN_STARTED.getDesc());
        }
        if (sort < indexAct) {
            nano = nano + 24 * 3600;
            item.setState(BatchStatusEnum.TOMORROW_START.getDesc());
        }
        LocalTime currTime = LocalTime.now().withNano(0);
        long currentMils = currTime.toSecondOfDay();
        item.setStop(String.valueOf(nano - currentMils));
    }

    /**
     * 根据批次号计算结算时间
     * @param batch
     * @return
     */
    public int calStopTime(DtsSeckillBatch batch) {
        int indexAct = this.calcCurrentIndexAct();
        int sort = batch.getSort();
        int nano = batch.getEndTime().toSecondOfDay();
        if (sort != indexAct) {
            nano = batch.getStartTime().toSecondOfDay();
        }
        if (sort < indexAct) { // 如果在当前批次之前
            nano = nano + 24 * 3600;
        }
        LocalTime currTime = LocalTime.now().withNano(0);
        int currentMils = currTime.toSecondOfDay();
        return nano - currentMils;
    }

    public void subscribe(Integer userId, @NotNull Integer id, Integer timeStatus) {
        Map<String, Object> params = new HashMap<>(16);
        params.put("userId", userId);
        params.put("goodsId", id);
        params.put("timeStatus", timeStatus);
        Integer subscribed = dtsUserSeckillSubService.selectNotifyExists(params);
        if (subscribed.equals(0)) {
            dtsUserSeckillSubService.subscribe(userId, id, timeStatus);
        }
    }

    public int isSubscribe(Integer userId, @NotNull Integer id, Integer timeStatus) {
        Map<String, Object> params = new HashMap<>(16);
        params.put("userId", userId);
        params.put("goodsId", id);
        params.put("timeStatus", timeStatus);
        return seckillGoodsService.isSubscribe(params);
    }

    /**
     * 指定批次商品
     * @param userId 当前登录用户
     * @param batchId 批次Id
     * @return
     */
    public List<SeckillGoodsVo> getBatchSeckillGoodByBatchId(Integer userId, int batchId) {
        final int currentIndexAct = this.calcCurrentIndexAct();
        return seckillGoodsService.getBatchSeckillGoodByBatchId(userId, batchId, currentIndexAct);
    }

    /**
     * 如果当前批次有秒杀活动优先展示
     * 如果当前批次没有秒杀活动就展示普通商品售卖形式
     *
     * @return
     */
    public Map<String, Object> getCurrBatchSeckillGood(Integer userId, int offset, int limit) {
        Map<String, Object> map = new HashMap<>();
        final int currentIndexAct = this.calcCurrentIndexAct();
        List<DtsSeckillBatch> timeBatchConfigs = getTimeBatchConfigs();
        List<SeckillGoodsVo> seckillAllGoods = new ArrayList<>();
        timeBatchConfigs.forEach(item -> {
            int actIndex = item.getSort();
            List<SeckillGoodsVo> seckillGoods = seckillGoodsService.getBatchSeckillGoodByBatchId(userId, actIndex, currentIndexAct);
            seckillAllGoods.addAll(seckillGoods);
        });
        if (seckillAllGoods != null && seckillAllGoods.size() < limit) {
            limit = seckillAllGoods.size();
        }
        List<SeckillGoodsVo> resSeckillGoods = seckillAllGoods.subList(offset, limit);
        map.put("seckillList", resSeckillGoods);
        map.put("currentIndexAct", currentIndexAct);
        return map;
    }

    /**
     * 做秒杀操作,如果满足条件，生成秒杀商品购物车信息，并返回抢购状态
     * @return 秒杀状态
     */
    public SeckillStatus doSeckill(int userId, int seckillGoodsId, int productId, int productNum) {
        SeckillStatus seckillStatus = seckillGoodsService.doSeckill(userId, seckillGoodsId, productId, productNum);
        return seckillStatus;
    }

    /**
     * 秒杀预告消息
     * @param batch
     * @return
     */
    public String noticeMsg(DtsSeckillBatch batch) {
        int indexAct = this.calcCurrentIndexAct();
        String result = batch.getTime();
        if (batch.getSort() < indexAct) {
            result = "明日 " + result;
        }
        return result;
    }

    /**
     * 根据秒杀货品过滤商品的规格
     * @param specificationList
     * @param dtsGoodsProducts
     * @return
     */
    public void filterSpecificationVoList(List<DtsGoodsSpecificationService.VO> specificationList, List<DtsGoodsProduct> dtsGoodsProducts) {
        if (specificationList != null && specificationList.size() > 0
                && dtsGoodsProducts != null && dtsGoodsProducts.size() > 0) {
            for (DtsGoodsSpecificationService.VO vo : specificationList) {
                excludeSpecifications(vo.getValueList(), dtsGoodsProducts);
            }
        }
    }

    /**
     * 删除货品记录中不存在的规格
     * @param valueList
     * @param dtsGoodsProducts
     */
    private void excludeSpecifications(List<DtsGoodsSpecification> valueList, List<DtsGoodsProduct> dtsGoodsProducts) {
        Iterator<DtsGoodsSpecification> iterator = valueList.iterator();
        while (iterator.hasNext()) {
            DtsGoodsSpecification specification = iterator.next();
            boolean delFalg = true;
            for (DtsGoodsProduct product : dtsGoodsProducts) {
                if (Arrays.asList(product.getSpecifications()).contains(specification.getValue())) {
                    // 包含规格文字，不能删除
                    delFalg = false;
                    break;
                }
            }
            if (delFalg) {
                iterator.remove();
            }
        }
    }

    /**
     * 根据用户秒杀选择的商品，获取缓存中购物信息
     * @param userId
     * @param seckillGoodsId
     * @return
     */
    public List<DtsCart> getCheckedCartForCache(Integer userId, Integer seckillGoodsId) {
        return seckillGoodsService.getCheckedCartForCache(userId, seckillGoodsId);
    }
}